package game.code;

import game.util.FReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.TreeMap;
/**
 * The Loader handles reading from the dictionary file( by extending class 
 * FReader), selecting a random six-letter word, and load all result sets 
 * derived from this six-letter word. Loader first loads all the words that 
 * have length between 3 to 6 into a Hashtable, and all words of length 6 
 * into an ArrayList. The advantage of using ArrayList is that it supports 
 * indexing, easier for random selection). Among the ArrayList, Loader will 
 * picks up a six-letter word, as the key word, and read from the hashtable 
 * containing all words from length 3-6 forms the result sets. Loader keeps 
 * all the result sets, in four different TreeMap, which maintains an ordered
 * collection.     
 * 
 * @author Ying R Zhao
 *
 */
public class Loader extends FReader{
	
	public static final int KEYWORD_LEN = 6 ; 
	public static final int MIN_WORD_LEN = 3 ; 
	
	/**
	 * the selected random six-letter word
	 */
	private String keyWord = null; 
	
	/**
	 * ordered collection. all three-letter words derived from the key words
	 */
	private TreeMap<String, Boolean> threeLetterWords; 
	
	/**
	 * ordered collection. all four-letter words derived from the key words
	 */
	private TreeMap<String, Boolean> fourLetterWords; 
	
	/**
	 * ordered collection. all five-letter words derived from the key words
	 */
	private TreeMap<String, Boolean> fiveLetterWords; 
	
	/**
	 * ordered collection. all six-letter words derived from the key words
	 */
	private TreeMap<String, Boolean> sixLetterWords;
	
	/**
	 * all the six-letter words for random selection. only load once.
	 */
	private ArrayList<String> allSixLetterWords;
	
	/**
	 * all words of length from 3 to 6 from dictionary.
	 */
	private Hashtable<String, Integer> allWords ; 
	
	public Loader(String fileName){                   
		//reader = new FReader(fileName);
		super(fileName);
		
		threeLetterWords = new TreeMap<String, Boolean>();
		fourLetterWords = new TreeMap<String, Boolean>();
		fiveLetterWords = new TreeMap<String, Boolean>();
		sixLetterWords = new TreeMap<String, Boolean>();
		
		allSixLetterWords = new ArrayList<String>();
		allWords = new Hashtable<String, Integer>();

	}
	
	/**
	 * load all words from the dictionary file into a Hashtable, and all 6-letter 
	 * words  into an arraylist.
	 * Only called once when the first time game starts. restart will not 
	 * call loadDictionary, because all words are already loaded into the hashtable
	 * and arraylist. 
	 */
	public void loadDictionary(){
		String line = null ; 
		
		try {
			while( ( line=reader.readLine() )!=null){
				if(isValidWord(line.toLowerCase())){
					allWords.put(line.toLowerCase(), line.length());
					
					if(line.length()==KEYWORD_LEN)
						allSixLetterWords.add(line.toLowerCase());
				}
			}
			
			reader.close(); 
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * will get rid of words with '-', ',', '.' etc. 
	 * will get rid of words length not between 3 and 6.
	 * @param str
	 * @return
	 */
	public boolean isValidWord(String str){
		
		if(str.length()<Loader.MIN_WORD_LEN || str.length()>Loader.KEYWORD_LEN)
			return false;
			
		for(char c : str.toCharArray()){

			int val = (int) (c -'a');
			
			if( val < 0 || val >=26 )
			{
				return false;
			}
		}
		
		return true; 
	}
	
	/**
	 * select a random six-letter word from the ArrayList.
	 * called after finish loading all the words from the file. 
	 */
	public void selectKeyWord(){
		//random from 0 to size of the six-letter arraylist.
		int random = (int)(Math.random()*allSixLetterWords.size());
		
		keyWord = allSixLetterWords.get(random); 
		//System.out.println(keyWord);
	}
	
	/**
	 * load all result sets derived from keyWord into each ArrayList 
	 */
	public void loadLetterWords(){
		//ignore case-sensitivity
		int[] flag = new int[26] ;  
		
		for(int i=0; i<Loader.KEYWORD_LEN; i++){
			flag[keyWord.charAt(i)-'a']++;
		}
		
		//clear out if already loaded. (support user click the start second time)
		threeLetterWords.clear();
		fourLetterWords.clear();
		fiveLetterWords.clear();
		sixLetterWords.clear();
		
		for(String word : allWords.keySet()){
			//for every word in the keyset, instantiate a counter[], counts
			// number of occurrence of the key letters
			int [] count = flag.clone() ;  
			boolean isIn = true; 
			int len = word.length();
			
			for(int i=0; i<len; i++){
				count[word.charAt(i)-'a']--;
				
				if(count[word.charAt(i)-'a']<0){
					isIn = false;
					break;
				}
			
			}
			
			if(isIn){
				if(len==6)
					//true means this word has not been submitted by user
					sixLetterWords.put(word ,  true);
				else if(len==5)
					fiveLetterWords.put(word ,  true);
				else if(len==4)
					fourLetterWords.put(word ,  true);
				else if(len==3)
					threeLetterWords.put(word ,  true);
				else {
					
				}
			}
		}
		//remove the keyWord from result set
		//sixLetterWords.remove(keyWord);
		
		//System.out.println(threeLetterWords.toString());
		//System.out.println(fourLetterWords.toString());
		//System.out.println(fiveLetterWords.toString());
		//System.out.println(sixLetterWords.toString());
		
	}
	
	/**
	 * 
	 * @return total number of words(len >3 &&len <6) that in the result sets.
	 */
	public int getTotalNumOfResults(){
		int answer = 0;
		answer += threeLetterWords.size();
		answer += fourLetterWords.size();
		answer += fiveLetterWords.size();
		answer += sixLetterWords.size();
		return answer;
	}
	
	/**
	 * return the loaded 6-letter-word. must call after calling 
	 * loadKeyWord()
	 * @return the key word (6-letter-word)
	 */
	public String getKeyWord(){return keyWord;}
	
	/**
	 * must call load() first.
	 * @return arraylist of 3-letter-word 
	 */
	public TreeMap<String, Boolean> getThreeLetterWords( ){return threeLetterWords ;}
	
	/**
	 * must call load() first.
	 * @return arraylist of 4-letter-word 
	 */
	public TreeMap<String, Boolean> getFourLetterWords( ){return fourLetterWords ; }
	
	/**
	 * must call load() first.
	 * @return arraylist of 5-letter-word 
	 */
	public TreeMap<String, Boolean> getFiveLetterWords( ){return fiveLetterWords ; }
	
	/**
	 * must call load() first.
	 * @return arraylist of 6-letter-word 
	 */
	public TreeMap<String, Boolean> getSixLetterWords( ){return sixLetterWords ; }
	
	
}
